/**
 * @file    cgal_source_base.hpp
 * @author  fynkxo (fynkxo@163.com)
 * @brief   CGAL Surface_mesh 网格源基类
 * @version 0.1
 * @date    2025-07-03
 *
 * @copyright Copyright (c) 2025 fynkxo.
 *
 */
#include <CGAL/IO/STL.h>
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <filesystem>
#include <memory>
#include <vector>
#include <vtkBuffer.h>
#include <vtkSetGet.h>
#ifndef CGAL_SOURCE_BASE_HPP_
#define CGAL_SOURCE_BASE_HPP_ 1

#include "cgal_defines.hpp"

#include <vtkPolyDataAlgorithm.h>

namespace cgalView {
/**
 * @brief 类cgal_source实现CGAL Surface_mesh网格通用方法
 *
 * @author fynkxo
 * @date 2025年7月3日
 */
class cgal_source_base : public vtkPolyDataAlgorithm {
public:
  static cgal_source_base *New() { VTK_STANDARD_NEW_BODY(cgal_source_base); }

  vtkTypeMacro(cgal_source_base, vtkPolyDataAlgorithm);

protected:
  cgal_source_base() : vtkPolyDataAlgorithm() {
    this->SetNumberOfInputPorts(0);
    this->SetNumberOfOutputPorts(1);
  }

  ~cgal_source_base() {}

public:
  /**
   * @brief 加载CGAL Surface_mesh 网格对象
   *
   * @param mesh mesh
   */
  void load_mesh(std::shared_ptr<surfacemesh_type> mesh) { d_mesh = mesh; }

  /**
   * @brief 从文件中加载CGAL Surface_mesh 网格对象
   *
   * @param filename File name.
   * @return true
   * @return false
   */
  bool load_file(std::filesystem::path const &filename) {
    namespace fs = std::filesystem;
    d_mesh = std::make_shared<surfacemesh_type>();

    if (!fs::exists(filename)) {
      return false;
    }

    auto ext = filename.extension().string();
    if (ext.empty()) {
      return false;
    }
    std::transform(ext.begin(), ext.end(), ext.begin(),
                   [](char c) -> char { return std::tolower(c); });

    if (".stl" == ext || ".off" == ext || ".ply" == ext) {
      std::vector<point_type> points{};
      std::vector<std::vector<size_t>> faces{};

      auto b = CGAL::IO::read_STL(filename.string(), points, faces);
      if (!b) {
        return false;
      }

      namespace PMP = CGAL::Polygon_mesh_processing;
      PMP::repair_polygon_soup(points, faces);
      b = PMP::orient_polygon_soup(points, faces);
      if (!b) {
        return false;
      }
      PMP::polygon_soup_to_polygon_mesh(points, faces, *d_mesh);
      return true;
    }
    return false;
  }

  /**
   * @brief Get the CGAL Surface_mesh object
   *
   * @return std::shared_ptr<surfacemesh_type>
   */
  std::shared_ptr<surfacemesh_type> get_mesh() { return d_mesh; }

protected:
  std::shared_ptr<surfacemesh_type> d_mesh;
};
} // namespace cgalView
#endif // CGAL_SOURCE_BASE_HPP_